import {Injectable, Logger} from "@nestjs/common";
import * as net from "node:net";
import {breathConfig} from "../../../config";
import {WsGateway} from "../../ws/ws.gateway";
import {CallFilterService} from "../call-filter/call-filter.service";
import {Observable, Observer} from "rxjs";
import {each, throttle} from "lodash";
import {LogService} from "@app/log";

interface TypeRecord {
    type: "P" | "Z" | "";
    timestamp: number;
    isValid: Boolean;
    data_filter: number | string;
}

@Injectable()
export class SocketClientService {
    client = null;
    rawDataArr = [];
    tobeFilterDataArr = [];
    initDataCount = 0;
    rawStartIndex = 0;
    filterStartIndex = 0;
    latestSendPeakIndex = -1;
    latestSendValleyIndex = -1;

    record = {
        recordStartFlag: false, // 记录开始标志位
        scanStartFlag: false, // 扫描开始标志位
        recordArr: [] as TypeRecord[], // 记录数组
        recordRawDataArr: [], // 记录的原始数据
        recent1MinDataLength: 3000, // getRecent接口需要保存的数据长度。
        // recent1MinData: [],
        recordPeakTimestampArr: [],
        recordValleyTimestampArr: [],

        recent1MinPeakIndexArrSince0: [], //记录最近1分钟的波峰的索引，绝对索引
        recent1MinValleyIndexArrSince0: [], // 记录最近1分钟的波谷的索引，绝对索引
        recent1MinFilterData: [], //记录最近1分钟的滤波数据，配合起始索引。可以得到每一个数据的绝对索引。
        recent1MinFilterDataStartIndex: 0, ////记录最近1分钟滤波数据的起始索引
    };

    filter = {
        low: breathConfig.defaultFilterParams.low,
        hi: breathConfig.defaultFilterParams.hi,
        order: breathConfig.defaultFilterParams.order,
        yCenter: breathConfig.defaultFilterParams.yCenter,
        peak_threshold: breathConfig.defaultFilterParams.peak_threshold,
        valley_threshold: breathConfig.defaultFilterParams.valley_threshold,
        prominence_threshold: breathConfig.defaultFilterParams.prominence_threshold,
        min_distance: breathConfig.defaultFilterParams.min_distance,
    };

    breathInfo = {
        fdctAble: false,
        peakError: -1,
        breathFrequency: 0,
        frequency_error: -1,
        current_p: 0,
    };

    test_helper_count = {
        p_count_since_start: 0, // p的出现总数
        z_count_since_start: 0,

        p_count_in_start_time: -1, // 开始那一刻的p的数量
        z_count_in_start_time: -1,

        p_actual_count_since_record_start: 0, // 从记录开始时 --> 目前的p的总数，是实际值
        z_actual_count_since_record_start: 0, // 从记录开始时的z的总数，是实际值

        p_count_since_record_start: 0, // 从记录开始时我的记录到的p的总数，观察和上面的值是否匹配
        z_count_since_record_start: 0,
    };
    gatewaySocketClient = null


    constructor(
        private readonly wsGateway: WsGateway,
        private readonly callFilterService: CallFilterService,
        private readonly logger: LogService,
    ) {
        const ans: Observable<any> = this.callFilterService.waitMsg();
        ans.subscribe({
            next: (value) => {
                const {
                    data: currentTimeTotalFilterData,
                    peakIndex,
                    peakVals,
                    valleyIndex,
                    valleyVals,
                    bpm,
                    filterStartIndex: currentTimeFilterStartIndex,
                    peak_error,
                    freq_error,
                    last_freq,
                } = value;
                // console.log(`收到滤波响应, 原始数据的主频率为:${bpm},peak_error为：${peak_error}%, freq_error为:${freq_error}%,最新的频率为:${last_freq} BPM`);
                const latestFilterData: number[] = currentTimeTotalFilterData.slice(
                    currentTimeTotalFilterData.length - breathConfig.sendPackLength,
                );
                // 当前滤波的起始索引 + 当前滤波数据的长度 （稳定后为3000）- 要发送的包的长度（5） = 发送数据的起始索引。
                const sendPackStartIndex =
                    currentTimeFilterStartIndex +
                    (currentTimeTotalFilterData.length - breathConfig.sendPackLength);
                // console.log(`发送的滤波数据的起点为:${start}`,peakIndex, peakVals,valleyIndex,valleyVals,currentTimeFilterStartIndex, bpm);
                const {peakIndexArr, valleyIndexArr} = this.sendPeakOrValleyData(
                    peakIndex,
                    peakVals,
                    valleyIndex,
                    valleyVals,
                    currentTimeFilterStartIndex,
                );
                this.recordRecentPeakOrValley(peakIndexArr, valleyIndexArr);
                this.sendFilterData(latestFilterData, sendPackStartIndex);
                this.sendBreathInfo(bpm, peak_error, freq_error, last_freq);
                this.checkNeedSaveRecord(
                    latestFilterData,
                    sendPackStartIndex,
                    peakIndex,
                    valleyIndex,
                    currentTimeFilterStartIndex,
                );
                this.recordRecent1MinData(latestFilterData);
            }, // 每次发出值时的处理函数
            complete: () => {
                console.log("Observable completed");
                return "finish";
            }, // 完成时的处理函数
            error: (err) => console.error("Something went wrong: " + err), // 错误处理函数
        });
        if (breathConfig.openMockGateSignalFlag) {
            this.connectMockGatewaySocket()
        }
    }

    connect() {
        return new Promise((resolve, reject) => {
            this.client = new net.Socket();
            this.client.connect(
                breathConfig.socketServerPort,
                breathConfig.socketServerIp,
            );
            this.client.setTimeout(5000);

            this.client.on("connect", () => {
                let uint8Array = new Uint8Array(breathConfig.openCmd);
                this.client.write(uint8Array);
                console.log("connect");
            });
            this.client.on("finish", () => console.log("finish"));
            this.client.on("error", (e) => {
                reject("error");
                console.log("error", e);
                this.resetVal();
            });
            this.client.on("timeout", (e) => {
                reject("timeout");
                console.log("timeout", e);
                this.resetVal();
            });
            this.client.on("data", async (data) => {
                resolve("");
                this.receiveData(data);
            });
        });
    }

    connectMockGatewaySocket() {
        this.gatewaySocketClient = new net.Socket();
        this.gatewaySocketClient.connect(
            breathConfig.mockGatewaySignalPort,
            breathConfig.socketServerIp,
        );

        this.gatewaySocketClient.on("connect", () => {
            console.log("gateway socket connect");
        });
        this.gatewaySocketClient.on("error", (e) => {
            console.log("error", e);
        });
        this.gatewaySocketClient.on("data", async (data) => {
            const arrayData = Array.from(data);
            const breathInfoMsg = {
                name: "gate_signal",
                signal: arrayData[0],
            };
            this.wsGateway.sendMsg(breathInfoMsg);
        });
    }

    close() {
        try {
            let uint8Array = new Uint8Array(breathConfig.closeCmd);
            this.client.write(uint8Array);
            this.client.destroy();
            this.client = null;
            this.resetVal();
        }catch (e) {
            console.log("关闭呼吸数据采集设备出错,",e.message);
        }
    }

    resetVal() {
        Object.assign(this, {
            rawDataArr: [],
            tobeFilterDataArr: [],
            initDataCount: 0,
            rawStartIndex: 0,
            filterStartIndex: 0,
            latestSendPeakIndex: -1,
            latestSendValleyIndex: -1,

            record: {
                recordStartFlag: false, // 记录开始标志位
                scanStartFlag: false, // 扫描开始标志位
                recordArr: [], // 记录数组
                recordRawDataArr: [], // 记录的原始数据
                recent1MinDataLength: 3000, // getRecent接口需要保存的数据长度。

                recordPeakTimestampArr: [],
                recordValleyTimestampArr: [],

                recent1MinPeakIndexArrSince0: [], //记录最近1分钟的波峰的索引，绝对索引
                recent1MinValleyIndexArrSince0: [], // 记录最近1分钟的波谷的索引，绝对索引
                recent1MinFilterData: [], //记录最近1分钟的滤波数据，配合起始索引。可以得到每一个数据的绝对索引。
                recent1MinFilterDataStartIndex: 0, ////记录最近1分钟滤波数据的起始索引
            },

            filter: {
                low: breathConfig.defaultFilterParams.low,
                hi: breathConfig.defaultFilterParams.hi,
                order: breathConfig.defaultFilterParams.order,
                yCenter: breathConfig.defaultFilterParams.yCenter,
                peak_threshold: breathConfig.defaultFilterParams.peak_threshold,
                valley_threshold: breathConfig.defaultFilterParams.valley_threshold,
                prominence_threshold:
                breathConfig.defaultFilterParams.prominence_threshold,
                min_distance: breathConfig.defaultFilterParams.min_distance,
            },
            breathInfo: {
                fdctAble: false,
                peakError: -1,
                breathFrequency: 0,
                frequency_error: -1,
                current_p: 0,
            },
            test_helper_count: {
                p_count_since_start: 0, // p的出现总数
                z_count_since_start: 0,

                p_count_in_start_time: -1, // 开始那一刻的p的数量
                z_count_in_start_time: -1,

                p_actual_count_since_record_start: 0, // 从记录开始时 --> 目前的p的总数，是实际值
                z_actual_count_since_record_start: 0, // 从记录开始时的z的总数，是实际值

                p_count_since_record_start: 0, // 从记录开始时我的记录到的p的总数，观察和上面的值是否匹配
                z_count_since_record_start: 0,
            },
        });
    }

    receiveData(data) {
        const arr: number[] = Array.from(data);
        const dataCount = arr.length / 4;
        for (let i = 0; i < dataCount; i++) {
            const data = (arr[4 * i + 2] << 8) + arr[4 * i + 3];
            this.rawDataArr.push(data);
            this.initDataCount++;
        }
        this.checkRawDataLengthFit();
    }

    checkRawDataLengthFit() {
        if (this.rawDataArr.length < breathConfig.sendPackLength) {
            return;
        }
        const needSendRawArr = this.rawDataArr.splice(
            0,
            breathConfig.sendPackLength,
        );
        this.sendRawData(needSendRawArr);
        if (this.tobeFilterDataArr.length >= breathConfig.filterDataMaxLength) {
            this.filterStartIndex =
                this.filterStartIndex +
                (this.tobeFilterDataArr.length - breathConfig.filterDataMaxLength);
            this.tobeFilterDataArr = this.tobeFilterDataArr.slice(
                this.tobeFilterDataArr.length - breathConfig.filterDataMaxLength,
            );
        }

        this.tobeFilterDataArr = [...this.tobeFilterDataArr, ...needSendRawArr];
        // console.log(`调用滤波：${this.filterStartIndex},${this.tobeFilterDataArr.length}`);
        // console.log(`调用滤波：${JSON.stringify(this.filter)}`);
        this.callFilterService.sendMsg({
            ...this.filter,
            data: this.tobeFilterDataArr,
            filterStartIndex: this.filterStartIndex,
        });
    }

    sendRawData(rawData: number[]) {
        const rawDataMsg = rawData.map((eachData, index) => {
            const timestamp =
                (this.rawStartIndex + index) * breathConfig.eachDataInterval;
            return {
                value: [timestamp, eachData],
            };
        });
        // console.log(`发送原始数据，索引为:${this.rawStartIndex},长度为:${rawDataMsg.length},共收到初始数据为:${this.initDataCount}`);
        this.rawStartIndex = this.rawStartIndex + rawData.length;
        this.sendMsg(rawDataMsg, "Breathe-origin");
    }

    sendFilterData(filterData: number[], start: number) {
        // console.log(`发送滤波数据：${filterData}`);

        const filterDataMsg = filterData.map((eachData, index) => {
            const timestamp = (start + index) * breathConfig.eachDataInterval;
            return {
                value: [timestamp, eachData],
            };
        });
        // console.log(`发送滤波数据，索引为:${start},长度为:${filterDataMsg.length},共收到初始数据为:${this.initDataCount}\``);
        this.sendMsg(filterDataMsg, "Breathe-filter");
    }

    sendMsg(msg, type) {
        this.wsGateway.sendMsg({
            name: type,
            breatheVoList: msg,
        });
    }

    modifyFilter(newFilter, initFlag) {
        // 修改滤波参数的时候，要限制计算波峰波谷，因为如果对于3000个点的滤波。修改参数后会重新计算：波峰谷和滤波数据。
        // 但是已经发送给前端的滤波数据不会变就会导致波峰谷和滤波数据不匹配的问题。
        if (!initFlag) {
            this.latestSendValleyIndex =
                this.filterStartIndex +
                this.tobeFilterDataArr.length +
                breathConfig.no_show_peak_valley_if_modify_filter_points;
            this.latestSendPeakIndex =
                this.filterStartIndex +
                this.tobeFilterDataArr.length +
                breathConfig.no_show_peak_valley_if_modify_filter_points;
        }
        Object.assign(this.filter, newFilter);
    }

    sendPeakOrValleyData = (
        peakIndex: number[],
        peakData: number[],
        valleyIndex: number[],
        valleyData: number[],
        filterPackStart: number,
    ) => {
        let peakIndexArr = [],
            valleyIndexArr = [];
        const peaks = peakData
            .map((eachData, index) => {
                const currentIndex = filterPackStart + peakIndex[index];
                if (currentIndex <= this.latestSendPeakIndex) {
                    // console.log("该点已经发出:波峰", currentIndex, this.latestSendPeakIndex);
                    return null;
                }
                this.test_helper_count.p_count_since_start++;

                if (this.record.recordStartFlag) {
                    this.record.recordPeakTimestampArr.push(
                        currentIndex * breathConfig.eachDataInterval,
                    );
                }
                peakIndexArr.push(currentIndex);
                // console.log(`发出波峰index：${currentIndex}, 最近一次发出的波峰index为：${this.latestSendPeakIndex}，总的index数组为:${peakIndex}, 起始为：${filterPackStart}`);
                this.latestSendPeakIndex =
                    currentIndex + breathConfig.defaultFilterParams.min_distance;
                return [currentIndex * breathConfig.eachDataInterval, eachData];
            })
            .filter((item) => item !== null);

        const through = valleyData
            .map((eachData, index) => {
                const currentIndex = filterPackStart + valleyIndex[index];
                if (currentIndex <= this.latestSendValleyIndex) {
                    return null;
                }
                valleyIndexArr.push(currentIndex);
                this.test_helper_count.z_count_since_start++;
                if (this.record.recordStartFlag) {
                    this.record.recordValleyTimestampArr.push(
                        currentIndex * breathConfig.eachDataInterval,
                    );
                }

                // console.log(`发出波谷index：${currentIndex}, 最近一次发出的波谷index为：${this.latestSendValleyIndex}`);
                this.latestSendValleyIndex =
                    currentIndex + breathConfig.defaultFilterParams.min_distance;
                return [currentIndex * breathConfig.eachDataInterval, eachData];
            })
            .filter((item) => item !== null);
        if (peaks.length === 0 && through.length === 0) {
            return {
                peakIndexArr: [],
                valleyIndexArr: [],
            };
        }
        this.wsGateway.sendMsg({
            name: "markpoint",
            markpoint: {
                peak: peaks,
                through: through,
            },
        });
        return {
            peakIndexArr,
            valleyIndexArr,
        };
    };

    sendBreathInfo = throttle((bpm, peak_error, freq_error, last_freq) => {
        this.breathInfo.current_p = Math.round(bpm);
        this.breathInfo.peakError = peak_error;
        this.breathInfo.frequency_error = freq_error;
        this.breathInfo.breathFrequency = last_freq;

        if (
            this.breathInfo.peakError === -1 ||
            this.breathInfo.frequency_error === -1 ||
            (this.breathInfo.peakError === 0 && this.breathInfo.frequency_error === 0)
        ) {
            this.breathInfo.fdctAble = false;
        } else {
            this.breathInfo.fdctAble =
                peak_error <= breathConfig.stable_breath_condition.peak_error_within &&
                freq_error <= breathConfig.stable_breath_condition.freq_error_within;
        }

        const breathInfoMsg = {
            name: "fdct_info1",
            faultScanCycleNumber: this.breathInfo,
        };
        this.wsGateway.sendMsg(breathInfoMsg);
    }, 300);

    recordStart() {
        this.record.recordStartFlag = true;
        // 开始记录那一刻记录p 和z的长度。
        this.test_helper_count.p_count_in_start_time =
            this.test_helper_count.p_count_since_start;
        this.test_helper_count.z_count_in_start_time =
            this.test_helper_count.z_count_since_start;
    }

    scanStart() {
        this.record.scanStartFlag = true;
    }

    scanEnd() {
        this.record.scanStartFlag = false;
    }

    recordEnd() {
        const test_helper_count = this.test_helper_count;
        test_helper_count.p_actual_count_since_record_start =
            test_helper_count.p_count_since_start -
            test_helper_count.p_count_in_start_time;
        test_helper_count.z_actual_count_since_record_start =
            test_helper_count.z_count_since_start -
            test_helper_count.z_count_in_start_time;
        console.log(`记录结束。 
                 记录结束的时候我计算收到了p的数量：${this.record.recordPeakTimestampArr.length},
    实际应该收到的数量为:${test_helper_count.p_actual_count_since_record_start} = ${test_helper_count.p_count_since_start} - ${test_helper_count.p_count_in_start_time}`);

        console.log(`记录结束。 
                 记录结束的时候我计算收到了z的数量：${this.record.recordValleyTimestampArr.length},
    实际应该收到的数量为:${test_helper_count.z_actual_count_since_record_start} = ${test_helper_count.z_count_since_start} - ${test_helper_count.z_count_in_start_time}`);

        this.record.recordStartFlag = false;
        const ansArr = this.record.recordArr.slice(0);
        this.record.recordPeakTimestampArr.map((eachPeakTimestamp) => {
            const index = ansArr.findIndex(({timestamp}, index) => {
                return timestamp === eachPeakTimestamp;
            });
            if (index !== -1) {
                ansArr[index].type = "P";
            }
        });

        this.record.recordValleyTimestampArr.map((eachPeakTimestamp) => {
            const index = ansArr.findIndex(({timestamp}, index) => {
                return timestamp === eachPeakTimestamp;
            });
            if (index !== -1) {
                ansArr[index].type = "Z";
            }
        });

        this.record.recordArr = [];
        return ansArr;
    }

    checkNeedSaveRecord(
        filterData: number[],
        sendPackStartIndex: number,
        peakIndex,
        valleyIndex,
        filterStartIndex,
    ) {
        if (!this.record.recordStartFlag) {
            return;
        }
        filterData.map((eachData, index) => {
            const dataIndexSince0 = sendPackStartIndex + index;
            const timestamp = dataIndexSince0 * breathConfig.eachDataInterval;
            this.record.recordArr.push({
                type: "",
                timestamp,
                isValid: this.record.scanStartFlag,
                data_filter: eachData,
            });
        });
    }

    // peakIndex,valleyIndex 都是相对于currentTimeFilterStartIndex
    recordRecent1MinData(latestFilterData) {
        const packLength = breathConfig.sendPackLength;
        if (
            this.record.recent1MinFilterData.length >=
            this.record.recent1MinDataLength
        ) {
            this.record.recent1MinFilterData.splice(0, packLength);
            this.record.recent1MinFilterDataStartIndex =
                this.record.recent1MinFilterDataStartIndex + packLength;
        }
        latestFilterData.map((eachData, index) => {
            let type = "";
            this.record.recent1MinFilterData.push({
                data_filter: eachData,
                timestamp:
                    (this.record.recent1MinFilterDataStartIndex +
                        this.record.recent1MinFilterData.length) *
                    breathConfig.eachDataInterval,
                mark: type,
            });
        });
    }

    recordRecentPeakOrValley(peakIndexArr, valleyIndexArr) {
        if (
            this.record.recent1MinPeakIndexArrSince0.length >=
            this.record.recent1MinDataLength
        ) {
            this.record.recent1MinPeakIndexArrSince0.splice(
                0,
                breathConfig.sendPackLength,
            );
        }
        if (
            this.record.recent1MinValleyIndexArrSince0.length >=
            this.record.recent1MinDataLength
        ) {
            this.record.recent1MinValleyIndexArrSince0.splice(
                0,
                breathConfig.sendPackLength,
            );
        }
        this.record.recent1MinPeakIndexArrSince0.push(...peakIndexArr);
        this.record.recent1MinValleyIndexArrSince0.push(...valleyIndexArr);
    }

    getRecent() {
        const recent1MinPeakIndex = this.record.recent1MinPeakIndexArrSince0.filter(
            (eachIndex) => {
                return eachIndex >= this.record.recent1MinFilterDataStartIndex;
            },
        );
        const recent1MinValleyIndex =
            this.record.recent1MinValleyIndexArrSince0.filter((eachIndex) => {
                return eachIndex >= this.record.recent1MinFilterDataStartIndex;
            });

        return this.record.recent1MinFilterData.map((eachData, index) => {
            const since0Index = index + this.record.recent1MinFilterDataStartIndex;
            if (recent1MinPeakIndex.includes(since0Index)) {
                eachData.mark = "P";
            } else if (recent1MinValleyIndex.includes(since0Index)) {
                eachData.mark = "Z";
            }
            return eachData;
        });
    }

    setAmplitude(amplitude: number) {
        const cmd = [0x00, 0x02, amplitude, 0x00];
        console.log(cmd);
        let uint8Array = new Uint8Array(cmd);
        this.client.write(uint8Array);
    }
}
